package com.ruoyi.business.service.impl;

import com.ruoyi.business.service.IProcessDifinitionService;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.ShiroUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.FilenameUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

@Service
public class ProcessDifinitionServiceImpl implements IProcessDifinitionService {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;


    @Override
    public Deployment deployDefinition(String realPath) throws FileNotFoundException {
        Deployment deployment=null;
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        String extension = FilenameUtils.getExtension(realPath);
        FileInputStream fileInputStream = new FileInputStream(realPath);
        if(extension.equals("zip")) {
            ZipInputStream zipInputStream = new ZipInputStream(fileInputStream);
            deploymentBuilder.addZipInputStream(zipInputStream);
        }else {
            deploymentBuilder.addInputStream(realPath,fileInputStream);
        }
        deployment = deploymentBuilder.deploy();
        return deployment;
    }

    @Override
    public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) {
        return repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .singleResult();

    }

    @Override
    public InputStream getProcessDefinitionFileByDeploymentId(Long deploymentId) {
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(String.valueOf(deploymentId))
                .singleResult();

        String resourceName = definition.getResourceName();

        InputStream resourceAsStream = repositoryService.getResourceAsStream(String.valueOf(deploymentId), resourceName);


        return resourceAsStream;
    }

    @Override
    public InputStream getProcessDefinitionImageByDeploymentId(Long deploymentId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(String.valueOf(deploymentId))
                .singleResult();

        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());

        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator();

        InputStream inputStream = defaultProcessDiagramGenerator.generateDiagram(model,
                Collections.emptyList(),
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体");
        return inputStream;
    }

    @Override
    public ProcessInstance startProcessDefinition(String definitionKey, String businessKey, HashMap<String, Object> map) {

        return runtimeService.startProcessInstanceByKey(definitionKey,businessKey,map);
    }

    @Override
    public List<Task> getTaskByInstanceId(String id) {
        return taskService.createTaskQuery()
                .processInstanceId(id)
                .list();
    }

    @Override
    public void setTaskCandidateUser(String id, String valueOf) {
     taskService.addCandidateUser(id,valueOf);
    }

    @Override
    public InputStream getProcessImgByInstanceId(String instanceId) {
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId)
                .singleResult();
        if(processInstance== null) {
            throw new BusinessException("流程实例不存在");
        }

        //获取bpmn模型对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        //获取当前处于活动中的节点id
        List<String> activeActivityIds = Collections.emptyList();
        //检查当前流程是否已经结束
        if(processInstance.getEndTime() == null) {

            activeActivityIds = runtimeService.getActiveActivityIds(instanceId);
        }


        return generateProcessImg(bpmnModel,activeActivityIds,Collections.emptyList());
    }

    @Override
    public void deleteProcessInstance(String instanceId, String s) {
        //只会将runtime表中相关数据删除，history中的记录还会保留，并且会记录删除理由
        //将所有的流程节点自动设置为finished
        runtimeService.deleteProcessInstance(instanceId,s);
    }

    @Override
    public long getCountBydefinitionKey(String definitionKey, String userId) {

        return taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskCandidateOrAssigned(userId)
                .count();
    }

    @Override
    public List<Task> getTaskByDifinitionKeyAndUserId(String definitionKey, String userId, int startIndex, Integer pageSize) {
        return taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskCandidateOrAssigned(userId)
                .orderByTaskCreateTime()
                .asc()
                .listPage(startIndex,pageSize);
    }

    @Override
    public ProcessInstance getInstanceById(String processInstanceId) {

        return runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
    }

    @Override
    public Task getTaskById(String taskId) {
        return taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
    }

    @Override
    public void claimAndComment(Task task, boolean auditStatus, String comment) {
        //领取任务
        taskService.claim(task.getId(), ShiroUtils.getUserId().toString());
        //添加批注
        String prefix = auditStatus ? "[同意]":"[拒绝]";
        taskService.addComment(task.getId(),task.getProcessInstanceId(),prefix+comment);
        //完成任务
        Map<String, Object> variable = new HashMap<>();
        variable.put(task.getTaskDefinitionKey(),auditStatus);
        this.setVariables(task.getId(),variable);

        taskService.complete(task.getId()) ;
    }

    @Override
    public void claimAndComment(String taskId, Map<String, Object> variables, String comment) {
        //获取任务对象
        Task task = this.getTaskById(taskId);
        //  添加批注
        this.addTaskComment(taskId,task.getProcessInstanceId(),comment);
        //覆盖流程变量
        this.setVariables(taskId,variables);
        //完成任务
        taskService.complete(taskId);
    }

    @Override
    public void addTaskComment(String taskId, String instanceId, String comment) {
        taskService.addComment(taskId,instanceId,comment);
    }

    @Override
    public void setVariables(String taskId, Map<String, Object> map) {
         taskService.setVariables(taskId,map);
    }

    @Override
    public long getFinishedTaskCountByInstanceAuditUserId(String definishionKey, String userId) {
        return  historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(definishionKey)
                .taskAssignee(userId)
                .finished()
                .count();
    }

    @Override
    public HistoricProcessInstance getHistoryProcessInstanceByInstanceId(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
    }

    @Override
    public List<HistoricActivityInstance> getHistoricActivityListByInstanceId(String instanceId) {
        return historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .activityType("userTask")
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();
    }

    @Override
    public String getTaskCommentByTaskId(String taskId) {
        List<Comment> comments = taskService.getTaskComments(taskId);
         if(CollectionUtils.isEmpty(comments)) {
             return "";
         }
         //获取第一条批注的文本内容
        return comments.get(0).getFullMessage();
    }

    @Override
    public List<HistoricTaskInstance> getFinishedTaskListByInstanceAuditUserId(String definishionKey, String userId,Integer start,Integer pageSize) {
        return  historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(definishionKey)
                .taskAssignee(userId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .listPage(start,pageSize);
    }

    private InputStream generateProcessImg(BpmnModel bpmnModel,List<String> highLightedActivities,List<String> highLightedFlows) {
        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator();
        return defaultProcessDiagramGenerator.generateDiagram(bpmnModel,
                highLightedActivities,
                highLightedFlows,
                "宋体",
                "宋体",
                "宋体"
        );
    }


}
